﻿using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;

class GlobalVar
{
    private static string p_lograwfile_path = @"C:\vexredus\vexredus-log-raw.txt";
	public static string lograwfile_path { get { return p_lograwfile_path; } set { p_lograwfile_path = value; } }

    private static string p_uploadfile_path = @"C:\vexredus\vexredus-log-upload.txt";
    public static string uploadfile_path { get { return p_uploadfile_path; } set { p_uploadfile_path = value; } }


    private static string p_telin_buffer = "";
    public static string telin_buffer { get { return p_telin_buffer; } set { p_telin_buffer = value; } }

    /* REMOVE
    private static string p_access_path_writer = @"C:\Users\Sven\Desktop\access_path_writer.txt";
    public static string access_path_writer { get { return p_access_path_writer; } set { p_access_path_writer = value; } }

    private static string p_access_path_reader = @"C:\Users\Sven\Desktop\access_path_reader.txt";
    public static string access_path_reader { get { return p_access_path_reader; } set { p_access_path_reader = value; } }
    */


}


class PortDataReceived
{

    public static void Main()
    {
		string recvBuffer = "";
		string[] msgList;
		string msg = ""; 
		
        string serialport_name = "COM5";
		string serialport_baudrate_s = "";
        int serialport_baudrate = 57600;

        Console.WriteLine("Current Port: " + serialport_name);
        Console.WriteLine("Current Baudrate: " + serialport_baudrate);

        Console.Write("Change Settings? [y/n or any other key] ");
        if (Console.ReadLine() == "y")
        {
	        Console.Write("Set Portnumber [COM3,COM4,/dev/ttyUSB0,...] (default: COM5): ");
	        serialport_name = "" + Console.ReadLine();
			if(serialport_name == "") {
				serialport_name = "COM5";
			}

			Console.WriteLine("Current Port: " + serialport_name);
			
            Console.Write("Set Baudrate [57600, 115200]: (default: 57600): ");
			serialport_baudrate_s = Console.ReadLine();
			if(serialport_baudrate_s == "") {
				serialport_baudrate_s = "57600";
			}
            serialport_baudrate = Convert.ToInt32(serialport_baudrate_s);

			
            Console.WriteLine("Current Baudrate: " + serialport_baudrate);
        }
		
		SerialPort mySerialPort = new SerialPort(serialport_name);
		
		mySerialPort.BaudRate = serialport_baudrate;
        mySerialPort.Parity = Parity.None;
        mySerialPort.StopBits = StopBits.One;
        mySerialPort.DataBits = 8;
        mySerialPort.Handshake = Handshake.None;
		//mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
		
		while(!mySerialPort.IsOpen) {
			try
			{
	        	mySerialPort.Open();
				Console.WriteLine ("Serial port opened.");
			}
			catch(IOException e)
			{
				Console.WriteLine ("Couldn't open serial port: " + serialport_name);
				Console.WriteLine (e.ToString ().Split('\n')[0]);
				Thread.Sleep(1000);
				//return;
			}
		}
		
		// INCOMING UDP
        UdpClient u_in = new UdpClient(65002, AddressFamily.InterNetwork);
		
		// OUTGOING UDP
		UdpClient u_out = new UdpClient();
		//u_out.Connect("localhost", 65001);
		
		

        //Console.WriteLine("Waiting for Data...! Press Enter to activate upload capability!");
        //Console.ReadLine(); 
        //Console.WriteLine("Upload capability activated!");

        var heartbeat_timer = new Stopwatch();
        heartbeat_timer.Start();
        

        for (;;)
        {
			
			try {
	            if(mySerialPort.BytesToRead > 0) {
					string indata = "";
					try {
						indata = mySerialPort.ReadExisting ();
						
					}
					catch (IOException e) {
						Console.WriteLine ("Couldn't open serial port: " + serialport_name);
						Console.WriteLine (e.ToString ().Split('\n')[0]);
						Thread.Sleep(1000);
					}
					
					recvBuffer += indata;
					Console.Write(indata);
					
					// Write to log
					var fs = File.Open(GlobalVar.lograwfile_path, FileMode.Append, FileAccess.Write, FileShare.Read);
	        		var sw = new StreamWriter(fs);
	       			sw.AutoFlush = true;
			        sw.Write(indata);
			        //Console.WriteLine("DEBUG: indata: \"" + indata + '"');
			        sw.Close();
			        
					// Send to UDP
					/*u_out.Connect("localhost", 65001);
			        u_out.Send(ASCIIEncoding.UTF32.GetBytes(indata), ASCIIEncoding.UTF32.GetByteCount(indata));
					u_out.Close();*/
					
					// Split into messages, for UDP flow control
					if(recvBuffer.IndexOf ('\n') > 0) {
						msgList = recvBuffer.Split('\n');
						for(int i=0;i<msgList.Length-1;i++) {
							msg = msgList[i] + '\n';
							//Console.WriteLine("DEBUG: msg: \"" + msg + '"');
							try {
								// Send to UDP
								// Always try to open new connection (continous reconnect).
								u_out.Connect("localhost", 65001);
			        			u_out.Send(ASCIIEncoding.UTF32.GetBytes(msg), ASCIIEncoding.UTF32.GetByteCount(msg));
							}
							catch(SocketException e) {
								// Do nothing
								Console.WriteLine("DEBUG: " + e.ToString ().Split('\n')[0]);
							}
							//u_out.Close();
							Thread.Sleep(10); // Actual flow control: 10ms delay between messages
						}
						recvBuffer = recvBuffer.Substring(recvBuffer.IndexOf ('\n')+1);
					}
				}
			}
			catch (IOException e) {
				Console.WriteLine ("Couldn't open serial port: " + serialport_name);
				Console.WriteLine (e.ToString ().Split('\n')[0]);
				Thread.Sleep(1000);
			}
			
			// Check for incoming UDP
            if (u_in.Available > 0)
            {

                IPEndPoint e = new IPEndPoint(IPAddress.Any, 0);
                byte[] b = u_in.Receive(ref e);
                string readData = ASCIIEncoding.UTF32.GetString(b);
                mySerialPort.Write(readData + '\n');
                Console.WriteLine("Uploaded: " + readData);

                // Write to Upload log
                var fs_upload = File.Open(GlobalVar.uploadfile_path, FileMode.Append, FileAccess.Write, FileShare.Read);
                var sw_upload = new StreamWriter(fs_upload);
                sw_upload.AutoFlush = true;
                sw_upload.WriteLine(DateTime.Now + "," + readData);
                sw_upload.Close();

                heartbeat_timer.Restart();
            }
            else
            {
                if (heartbeat_timer.ElapsedMilliseconds > 5000)
                {
                    mySerialPort.Write("$RHB" + '\n');
                    Console.WriteLine("#HB#");
                    heartbeat_timer.Restart();
                }
            }




        }

        //Console.WriteLine("Press Enter to exit! Waiting for Data...");
        //Console.ReadLine();



    }

    /*private static void DataReceivedHandler(
                        object sender,
                        SerialDataReceivedEventArgs e)
    {
		Console.WriteLine ("DataReceivedHandler called");
        SerialPort sp = (SerialPort)sender;
        string indata = sp.ReadExisting();


        var fs = File.Open(GlobalVar.lograwfile_path, FileMode.Append, FileAccess.Write, FileShare.Read);
        var sw = new StreamWriter(fs);
        sw.AutoFlush = true;
        sw.Write(indata);
        Console.WriteLine(indata);
        sw.Close();


        string s = indata; // data to send
        UdpClient u1 = new UdpClient();
        u1.Connect("localhost", 65001);
        u1.Send(ASCIIEncoding.UTF32.GetBytes(s), ASCIIEncoding.UTF32.GetByteCount(s));


    }*/
}